package com.jpm.jroguefx.utilities.tools;


import com.jpm.jroguefx.Monster;
import com.jpm.jroguefx.factories.MonsterFactory;
import com.jpm.jroguefx.types.MonsterAbility;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.text.Text;
import javafx.stage.Stage;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;

public class MonsterEditor extends Application {

    private MonsterFactory mf = MonsterFactory.getInstance();
    private Logger logger = Logger.getLogger(MonsterEditor.class.getName());
    private int index = 0;
    private Monster monster;
    private HashSet<CheckBox> checkSet = new HashSet<>();
    private HashSet<TextField> textSet = new HashSet<>();
    private ImageView iv;
    private Text total;
    int[] xp = new int[40];

    public MonsterEditor() {
        xp[0] = 20;
        for (int i = 1; i < xp.length; i++) {
            xp[i] = (int) (xp[i - 1] * 1.2);
        }
    }


    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        final Group root = new Group();

        total = new Text();
        total.setLayoutX(100);
        total.setLayoutY(100);
        root.getChildren().add(total);

        double y = 10;

        for (MonsterAbility ability : MonsterAbility.values()) {
            CheckBox cb = new CheckBox(ability.name());
            cb.setId(ability.name());
            checkSet.add(cb);

            cb.setLayoutX(300 + (((int) (y / 575)) * 200));
            cb.setLayoutY(y - (((int) (y / 575)) * 575));
            y += 25;

            root.getChildren().add(cb);
        }

        iv = new ImageView();
        iv.setFitWidth(100);
        iv.setPreserveRatio(true);
        iv.setSmooth(true);
        iv.setCache(true);
        root.getChildren().add(iv);

        y = 150;

        for (Method method : Monster.class.getDeclaredMethods()) {

            if (method.getName().startsWith("get")) {
                String attr = method.getName().substring(3);
                if (method.getReturnType() == String.class || method.getReturnType() == int.class) {
                    Text text = new Text(attr);
                    text.setLayoutX(10);
                    text.setLayoutY(y);

                    TextField tf = new TextField();
                    tf.setLayoutX(70);
                    tf.setLayoutY(y - 15);
                    tf.setId(attr);

                    if (attr.equalsIgnoreCase("id") || attr.equalsIgnoreCase("img")) {
                        tf.setEditable(false);
                    }
                    textSet.add(tf);

                    y += 30;

                    root.getChildren().add(tf);
                    root.getChildren().add(text);
                }
            }
        }

        Button back = new Button("<");
        Button fback = new Button("<<");
        Button fforward = new Button(">>");
        Button forward = new Button(">");

        back.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                save();
                if (index > 0) {
                    mf.get(--index);
                }
                load();
            }
        });

        fback.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                save();
                String group = monster.getGroup();
                while (monster.getGroup().equals(group) && index > 0) {
                    monster = mf.get(--index);
                }

                load();
            }
        });

        fforward.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                save();
                String group = monster.getGroup();
                while (monster.getGroup().equals(group) && index < mf.size() - 1) {
                    monster = mf.get(++index);
                }
                load();
            }
        });

        forward.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                save();
                if (index < mf.size() - 1) {
                    mf.get(++index);
                }
                load();
            }
        });

        fback.setLayoutX(50);
        fback.setLayoutY(600);
        back.setLayoutX(100);
        back.setLayoutY(600);
        forward.setLayoutX(150);
        forward.setLayoutY(600);
        fforward.setLayoutX(200);
        fforward.setLayoutY(600);

        root.getChildren().add(fback);
        root.getChildren().add(back);
        root.getChildren().add(forward);
        root.getChildren().add(fforward);

        Button write = new Button("Save");
        write.setLayoutX(600);
        write.setLayoutY(600);

        write.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                save();
                mf.write();
            }
        });

        root.getChildren().add(write);

        Button template = new Button("Template");
        template.setLayoutX(400);
        template.setLayoutY(600);

        template.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                save();
                String group = monster.getGroup();

                for (Monster nextMonster : mf) {

                    if (nextMonster.getGroup().equalsIgnoreCase(group)) {

                        nextMonster.setLvl(monster.getLvl());
                        nextMonster.setDmg(monster.getDmg());
                        nextMonster.setHd(monster.getHd());
                        nextMonster.setDex(monster.getDex());
                        nextMonster.setWis(monster.getWis());
                        nextMonster.setAc(monster.getAc());
                        nextMonster.setAbilities(monster.getAbilities());
                        nextMonster.setSummon(monster.getSummon());
                        nextMonster.setSumnum(monster.getSumnum());
                    }
                }
            }
        });

        root.getChildren().add(template);

        Button delete = new Button("Delete");
        delete.setLayoutX(800);
        delete.setLayoutY(600);

        delete.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                mf.remove(index);
                load();
            }
        });

        root.getChildren().add(delete);

        primaryStage.setTitle("Monster Editor");
        primaryStage.setScene(new Scene(root, 1500, 800));
        primaryStage.show();

        load();
    }

    private void load() {

        total.setText(index + 1 + "/" + mf.size());
        monster = mf.get(index);

        for (CheckBox cb : checkSet) {
            cb.setSelected(monster.hasAbility(MonsterAbility.fromString(cb.getId())));
        }

        iv.setImage(monster.getImage());

        for (TextField tf : textSet) {

            try {
                Method method = monster.getClass().getDeclaredMethod("get" + tf.getId());

                if (method.getReturnType() == String.class || method.getReturnType() == int.class) {

                    Object obj = method.invoke(monster);

                    String field;
                    if (obj instanceof Integer) {
                        field = String.valueOf(obj);
                    } else {
                        field = (String) obj;
                    }

                    tf.setText(field);
                }
            } catch (NoSuchMethodException e) {
                logger.log(Level.SEVERE, "Can't find method for " + "set" + tf.getId(), e);
            } catch (InvocationTargetException e) {
                logger.log(Level.SEVERE, "Method " + "get" + tf.getId() + " thre exception", e);
            } catch (IllegalAccessException e) {
                logger.log(Level.SEVERE, "Access to method " + "get" + tf.getId() + " denied", e);
            }
        }
    }

    private void save() {

        for (CheckBox cb : checkSet) {
            monster.setAbility(MonsterAbility.fromString(cb.getId()), cb.isSelected());
        }

        for (TextField tf : textSet) {

            try {
                Method method = monster.getClass().getDeclaredMethod("set" + tf.getId(), String.class);
                method.invoke(monster, tf.getText());

            } catch (NoSuchMethodException e) {
                logger.log(Level.SEVERE, "Can't find method for " + "set" + tf.getId(), e);
            } catch (InvocationTargetException e) {
                logger.log(Level.SEVERE, "Method " + "get" + tf.getId() + " thre exception", e);
            } catch (IllegalAccessException e) {
                logger.log(Level.SEVERE, "Access to method " + "get" + tf.getId() + " denied", e);
            }
        }

        if (monster.getLvl() == 0) {
            monster.setLvl(1);
        }
        monster.setXp(xp[monster.getLvl() - 1]);
        monster.setHp(monster.getHd() * monster.getLvl());
        monster.setDmg(monster.getLvl());

    }
}



